﻿using Identity_Card.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Identity_Card
{
    public class IdentityCard
    {
        // 身份证
        protected static string idCard;

        // 区域
        protected static string locale;


        protected int[] constellationEdgeDays = new int[] { 21, 20, 21, 20, 21, 22, 23, 23, 23, 24, 22, 21 };

        // 星座
        protected Dictionary<string, string[]> constellations = new Dictionary<string, string[]>();

        // 中华人民共和国省行政区划代码（不包括香港、澳门和台湾地区）
        Dictionary<string, City> DicRegions = new Dictionary<string, City>();

        public IdentityCard()
        {
            // 星座（百度百科数据 https://baike.baidu.com/item/%E5%8D%A0%E6%98%9F%E5%AD%A6）
            constellations.Add("zh_cn", new string[] { "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座" });
            constellations.Add("en", new string[] { "Aquarius", "Pisces", "Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", "Capricorn" });

            // 加载 行政区划代码
            DicRegions = Regions.GetRegions();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="IdCard"></param>
        /// <param name="Locale"></param>
        /// <returns></returns>
        public static IdentityCard Init(string IdCard, string Locale = "zh_cn")
        {
            idCard = IdCard;
            locale = Locale;
            if (Check() == false)
            {

            }
            return new IdentityCard();
        }

        // 获取区域
        public static string GetLocale()
        {
            if (locale.Equals(""))
            {
                locale = "zh_cn";
            }

            return locale;
        }

        /// <summary>
        /// 检查 身份证号码 是否正确
        /// </summary>
        /// <returns></returns>
        public static bool Check()
        {
            string id = idCard.ToUpper();

            if (CheckFirst(id))
            {
                string iYear = id.Substring(6, 4);
                string iMonth = id.Substring(10, 2);
                string iDay = id.Substring(12, 2);
                if (IsDate(iYear + "-" + iMonth + "-" + iDay))
                {
                    return GetIDCardVerifyNumber(id.Substring(0, 17)) != id.Substring(17, 1) ? false : true;
                }
            }

            return false;

        }

        /// <summary>
        /// 通过正则表达式初步检测 身份证号码 是否正确
        /// </summary>
        /// <param name="idCard"></param>
        /// <returns></returns>
        public static bool CheckFirst(string idCard)
        {
            return Regex.IsMatch(idCard, @"^\d{6}(18|19|20)\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$");
        }

        /// <summary>
        /// 根据 身份证号码 的前17位数字计算最后校验位
        /// </summary>
        /// <param name="idcardBase"></param>
        /// <returns></returns>
        public static string GetIDCardVerifyNumber(string idcardBase)
        {
            int[] factor = new int[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

            char[] verifyNumberList = new char[] { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

            int checksum = 0;

            for (int i = 0; i < idcardBase.Length; i++)
            {
                checksum += int.Parse(idcardBase.Substring(i, 1)) * factor[i];
            }

            int mod = checksum % 11;

            return verifyNumberList[mod] + "";
        }

        /// <summary>
        /// 检查时间
        /// </summary>
        /// <param name="StrSource"></param>
        /// <returns></returns>
        public static bool IsDate(string StrSource)
        {
            return Regex.IsMatch(StrSource, @"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-9]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$");
        }

        /// <summary>
        /// 获取身份证地址
        /// </summary>
        /// <returns></returns>
        public string GetArea()
        {
            return GetProvince() + " " + GetCity() + " " + GetCounty();
        }

        /// <summary>
        /// 获取省级
        /// </summary>
        /// <returns></returns>
        public string GetProvince()
        {
            string k = idCard.Substring(0, 2) + "0000";

            switch (locale)
            {
                case "zh_cn":
                    return DicRegions[k].zh_cn;
                case "en":
                    return DicRegions[k].en;
                default:
                    return "";
            }
        }

        /// <summary>
        /// 获取市级
        /// </summary>
        /// <returns></returns>
        public string GetCity()
        {
            string k = idCard.Substring(0, 4) + "00";

            switch (locale)
            {
                case "zh_cn":
                    return DicRegions[k].zh_cn;
                case "en":
                    return DicRegions[k].en;
                default:
                    return "";
            }
        }

        /// <summary>
        /// 获取县级
        /// </summary>
        /// <returns></returns>
        public string GetCounty()
        {
            string k = idCard.Substring(0, 6);

            switch (locale)
            {
                case "zh_cn":
                    return DicRegions[k].zh_cn;
                case "en":
                    return DicRegions[k].en;
                default:
                    return "";
            }
        }

        /// <summary>
        /// 获取性别
        /// </summary>
        /// <returns></returns>
        public string GetGender()
        {
            Dictionary<string, Gender> GenderDic = new Dictionary<string, Gender>();
            GenderDic.Add("zh_cn", new Gender() { female = "女", male = "男" });
            GenderDic.Add("en", new Gender() { female = "Female", male = "Male" });
            Gender g = GenderDic[GetLocale()];

            return (int.Parse(idCard.Substring(16, 1)) % 2 == 0) ? g.female : g.male;
        }

        /// <summary>
        /// 获取生日
        /// </summary>
        /// <returns></returns>
        public string GetBirthday()
        {
            return idCard.Substring(6, 4) + "-" + idCard.Substring(10, 2) + "-" + idCard.Substring(12, 2);
        }

        /// <summary>
        /// 获取年龄
        /// </summary>
        /// <returns></returns>
        public int GetAge()
        {
            DateTime birthdate = new DateTime(int.Parse(idCard.Substring(6, 4)), int.Parse(idCard.Substring(10, 2)), int.Parse(idCard.Substring(12, 2)));
            DateTime now = DateTime.Now;
            int age = now.Year - birthdate.Year;
            if (now.Month < birthdate.Month || (now.Month == birthdate.Month && now.Day < birthdate.Day))
            {
                age--;
            }
            return age < 0 ? 0 : age;
        }

        /// <summary>
        /// 获取生肖
        /// </summary>
        /// <returns></returns>
        public string GetZodiac()
        {
            string[] zh = new string[] { "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪", "鼠" };
            string[] en = new string[] { "Cow", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Sheep", "Monkey", "Chicken", "Dog", "Pig", "Rat" };
            Dictionary<string, string[]> locale = new Dictionary<string, string[]>();
            locale.Add("zh_cn", zh);
            locale.Add("en", en);

            string[] g = locale[GetLocale()];

            int abs = Math.Abs(int.Parse(idCard.Substring(6, 4)) - 1901);
            int abs2 = abs % 12;

            return g[abs2];
        }

        /// <summary>
        /// 获取星座
        /// </summary>
        /// <returns></returns>
        public string GetConstellation()
        {
            int month = int.Parse(idCard.Substring(10, 2));

            month = month - 1;

            int day = int.Parse(idCard.Substring(12, 2));

            if (day < constellationEdgeDays[month])
            {
                month = month - 1;
            }

            if (month > 0)
            {
                return constellations[GetLocale()][month];
            }

            return constellations[GetLocale()][11];
        }

        /// <summary>
        /// 获取 JSON 格式数据
        /// </summary>
        /// <returns></returns>
        public string ToJson()
        {
            return JsonConvert.SerializeObject(ToDictionary());
        }

        /// <summary>
        /// 获取 Dictionary<string, string> 格式数据
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> ToDictionary()
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("area", GetArea());
            dic.Add("province", GetProvince());
            dic.Add("city", GetCity());
            dic.Add("county", GetCounty());
            dic.Add("Gender", GetGender());
            dic.Add("birthday", GetBirthday());
            dic.Add("zodiac", GetZodiac());
            dic.Add("age", GetAge() + "");
            dic.Add("constellation", GetConstellation());
            return dic;
        }
    }
}
